Learn in 10 minutes

Learn in 10 minutes

Aprenda Go em 10 minutos

Go (também conhecido como Golang) é uma linguagem de programação compilada e estaticamente tipada desenvolvida no Google. É conhecida por sua simplicidade, eficiência e excelente suporte para concorrência. Este tutorial vai ajudar você a aprender programação em Go rapidamente.

1. Escrevendo Seu Primeiro Programa em Go

Vamos começar com um programa simples. Crie um arquivo chamado hello.go e insira o seguinte código:

package main

import "fmt"

func main() {
    fmt.Println("Olá, Mundo!")
}

Salve o arquivo e execute o seguinte comando no terminal:

go run hello.go

A saída será:

Olá, Mundo!

Este programa simples demonstra a estrutura básica do Go:

  • package main declara o nome do pacote
  • import "fmt" importa o pacote de formatação para operações de E/S
  • func main() é o ponto de entrada do programa
  • fmt.Println() imprime texto no console

2. Sintaxe Básica

Go tem uma sintaxe limpa e simples. Diferente do Python, Go usa chaves {} para definir blocos de código e requer ponto e vírgula no final das instruções (embora geralmente sejam inseridos automaticamente).

// Este é um comentário de linha única
fmt.Println("Olá, Mundo!")

/*
Este é um comentário de múltiplas linhas
que abrange várias linhas
*/

Regras básicas de sintaxe em Go:

  • Blocos de Código: Definidos por chaves {}
  • Comentários: Comentários de linha única começam com //, de múltiplas linhas com /* */
  • Instruções: Terminam com ponto e vírgula (inseridos automaticamente)
  • Declaração de Pacote: Todo arquivo começa com uma declaração de pacote

3. Variáveis e Tipos de Dados

Go é estaticamente tipada, o que significa que você deve declarar os tipos das variáveis. No entanto, Go suporta inferência de tipos com o operador :=.

Métodos de declaração de variáveis:

// Declaração de tipo explícita
var nome string = "João"
var idade int = 25

// Inferência de tipo
nome := "João"
idade := 25

// Declaração múltipla de variáveis
var x, y int = 10, 20
x, y := 10, 20

Principais tipos de dados básicos do Go:

  • Tipos inteiros: int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr
  • Tipos float: float32, float64
  • String: string
  • Booleano: bool
  • Tipos complexos: complex64, complex128

3.1 Tipos Numéricos

Go fornece vários tipos numéricos para diferentes casos de uso:

// Tipos inteiros
var idade int = 25
var numeroPequeno int8 = 127
var numeroGrande int64 = 9223372036854775807

// Tipos float
var temperatura float32 = 36.5
var pi float64 = 3.14159265359

// Números complexos
var numeroComplexo complex64 = 3 + 4i

3.2 Tipo String

Strings em Go são sequências de bytes e são imutáveis:

// Declaração de string
var saudacao string = "Olá, Go!"
nome := "Alice"

// Operações com strings
fmt.Println(len(saudacao))        // Comprimento da string
fmt.Println(saudacao[0])          // Acessa primeiro caractere (byte)
fmt.Println(saudacao[0:5])        // Fatiamento de string
fmt.Println(strings.ToUpper(nome)) // Converte para maiúsculas

3.3 Tipo Booleano

O tipo booleano tem dois valores: true e false:

var estaAtivo bool = true
var estaCompleto bool = false

// Operações booleanas
resultado1 := true && false  // false
resultado2 := true || false  // true
resultado3 := !true          // false

4. Constantes

Constantes são declaradas usando a palavra-chave const e não podem ser alteradas:

const Pi = 3.14159
const MaxUsuarios = 1000

// Múltiplas constantes
const (
    StatusOK = 200
    StatusNaoEncontrado = 404
    StatusErro = 500
)

// Constantes tipadas
const Versao string = "1.0.0"

5. Estruturas de Dados

Go fornece várias estruturas de dados integradas para armazenar e manipular dados.

5.1 Arrays

Arrays são sequências de tamanho fixo de elementos do mesmo tipo:

// Declaração de array
var numeros [5]int = [5]int{1, 2, 3, 4, 5}
nomes := [3]string{"Alice", "Bob", "Charlie"}

// Acessando elementos
fmt.Println(numeros[0])  // 1
numeros[0] = 10         // Modifica elemento

// Comprimento do array
fmt.Println(len(numeros)) // 5

5.2 Slices

Slices são arrays dinâmicos que podem crescer e diminuir:

// Declaração de slice
numeros := []int{1, 2, 3, 4, 5}
var sliceVazio []int

// Criando slices a partir de arrays
arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:4]  // [2, 3, 4]

// Operações com slices
numeros = append(numeros, 6)      // Adiciona elemento
numeros = append(numeros, 7, 8, 9) // Adiciona múltiplos elementos

// Capacidade e comprimento do slice
fmt.Println(len(numeros)) // Comprimento: 9
fmt.Println(cap(numeros)) // Capacidade: 10 (pode variar)

5.3 Maps

Maps são coleções não ordenadas de pares chave-valor:

// Declaração de map
estudante := map[string]interface{}{
    "nome": "João",
    "idade":  20,
    "curso": "Ciência da Computação",
}

// Declaração alternativa
var notas map[string]int = make(map[string]int)
notas["matematica"] = 95
notas["ciencias"] = 88

// Acessando e modificando
fmt.Println(estudante["nome"])
estudante["idade"] = 21
estudante["media"] = 3.8

// Acesso seguro
if telefone, existe := estudante["telefone"]; existe {
    fmt.Println(telefone)
} else {
    fmt.Println("Telefone não fornecido")
}

// Iterando sobre o map
for chave, valor := range estudante {
    fmt.Printf("%s: %v\n", chave, valor)
}

5.4 Structs

Structs são coleções de campos que podem ter tipos diferentes:

// Definição de struct
type Pessoa struct {
    Nome string
    Idade  int
    Cidade string
}

// Criando instâncias de struct
pessoa1 := Pessoa{"Alice", 25, "Nova York"}
pessoa2 := Pessoa{
    Nome: "Bob",
    Idade:  30,
    Cidade: "Londres",
}

// Acessando campos
fmt.Println(pessoa1.Nome)
pessoa1.Idade = 26

6. Operações e Operadores

Go fornece um conjunto rico de operadores para vários cálculos e comparações.

  • Operadores Aritméticos: +, -, *, /, % (módulo)
  • Operadores de Comparação: ==, !=, >, <, >=, <=
  • Operadores Lógicos: &&, ||, !
  • Operadores Bitwise: &, |, ^, <<, >>
  • Operadores de Atribuição: =, +=, -=, *=, /=

6.1 Operadores Aritméticos

a, b := 10, 3

fmt.Printf("Adição: %d\n", a + b)      // 13
fmt.Printf("Subtração: %d\n", a - b)   // 7
fmt.Printf("Multiplicação: %d\n", a * b)  // 30
fmt.Printf("Divisão: %d\n", a / b)      // 3
fmt.Printf("Módulo: %d\n", a % b)      // 1

6.2 Operadores de Comparação

x, y := 5, 10

fmt.Printf("Igual: %t\n", x == y)     // false
fmt.Printf("Diferente: %t\n", x != y) // true
fmt.Printf("Maior que: %t\n", x > y)  // false
fmt.Printf("Menor que: %t\n", x < y)  // true

6.3 Operadores Lógicos

a, b := true, false

fmt.Printf("Operação AND: %t\n", a && b)  // false
fmt.Printf("Operação OR: %t\n", a || b)    // true
fmt.Printf("Operação NOT: %t\n", !a)    // false

7. Controle de Fluxo

Go fornece várias instruções de controle de fluxo para gerenciar a execução do programa.

7.1 Instruções if

idade := 20
if idade >= 18 {
    fmt.Println("Adulto")
} else if idade >= 13 {
    fmt.Println("Adolescente")
} else {
    fmt.Println("Criança")
}

// if com instrução curta
if nota := 85; nota >= 90 {
    fmt.Println("Nota: A")
} else if nota >= 80 {
    fmt.Println("Nota: B")
} else {
    fmt.Println("Nota: C")
}

7.2 Loops for

Go tem apenas um construto de loop: for

// Loop for básico
for i := 0; i < 5; i++ {
    fmt.Println(i)
}

// Loop estilo while
contador := 0
for contador < 5 {
    fmt.Println(contador)
    contador++
}

// Loop infinito
for {
    fmt.Println("Isso vai executar para sempre")
    break // Use break para sair
}

// Loop range (para slices, arrays, maps)
frutas := []string{"maçã", "banana", "cereja"}
for indice, fruta := range frutas {
    fmt.Printf("%d: %s\n", indice, fruta)
}

7.3 Instruções switch

dia := "Segunda-feira"
switch dia {
case "Segunda-feira":
    fmt.Println("Início da semana")
case "Sexta-feira":
    fmt.Println("Fim de semana está próximo")
case "Sábado", "Domingo":
    fmt.Println("Fim de semana!")
default:
    fmt.Println("Dia comum")
}

// Switch sem expressão
nota := 85
switch {
case nota >= 90:
    fmt.Println("Nota: A")
case nota >= 80:
    fmt.Println("Nota: B")
case nota >= 70:
    fmt.Println("Nota: C")
default:
    fmt.Println("Nota: F")
}

8. Funções

Funções em Go são cidadãos de primeira classe e suportam múltiplos valores de retorno.

8.1 Funções Básicas

func cumprimentar(nome string) string {
    return "Olá, " + nome + "!"
}

// Chamando a função
mensagem := cumprimentar("João")
fmt.Println(mensagem)

8.2 Múltiplos Valores de Retorno

func dividir(a, b float64) (float64, error) {
    if b == 0 {
        return 0, fmt.Errorf("não é possível dividir por zero")
    }
    return a / b, nil
}

// Usando múltiplos valores de retorno
resultado, err := dividir(10, 2)
if err != nil {
    fmt.Println("Erro:", err)
} else {
    fmt.Println("Resultado:", resultado)
}

8.3 Valores de Retorno Nomeados

func calcularRetangulo(largura, altura float64) (area float64, perimetro float64) {
    area = largura * altura
    perimetro = 2 * (largura + altura)
    return // retorno nu
}

area, perimetro := calcularRetangulo(5, 3)
fmt.Printf("Área: %.2f, Perímetro: %.2f\n", area, perimetro)

8.4 Funções Variádicas

func somar(numeros ...int) int {
    total := 0
    for _, num := range numeros {
        total += num
    }
    return total
}

fmt.Println(somar(1, 2, 3, 4))  // 10
fmt.Println(somar(5, 10, 15))   // 30

9. Ponteiros

Go tem ponteiros mas com sintaxe mais simples que C/C++:

func modificarValor(x *int) {
    *x = *x * 2
}

func main() {
    valor := 10
    fmt.Println("Antes:", valor) // 10

    modificarValor(&valor)
    fmt.Println("Depois:", valor)  // 20
}

10. Métodos

Métodos são funções com um argumento receptor:

type Retangulo struct {
    Largura  float64
    Altura float64
}

// Método com receptor de valor
func (r Retangulo) Area() float64 {
    return r.Largura * r.Altura
}

// Método com receptor de ponteiro
func (r *Retangulo) Escalar(fator float64) {
    r.Largura *= fator
    r.Altura *= fator
}

retangulo := Retangulo{Largura: 5, Altura: 3}
fmt.Println("Área:", retangulo.Area()) // 15

retangulo.Escalar(2)
fmt.Println("Área Escalada:", retangulo.Area()) // 60

11. Interfaces

Interfaces definem assinaturas de métodos que tipos podem implementar:

type Forma interface {
    Area() float64
    Perimetro() float64
}

type Circulo struct {
    Raio float64
}

func (c Circulo) Area() float64 {
    return 3.14159 * c.Raio * c.Raio
}

func (c Circulo) Perimetro() float64 {
    return 2 * 3.14159 * c.Raio
}

func imprimirInfoForma(s Forma) {
    fmt.Printf("Área: %.2f, Perímetro: %.2f\n", s.Area(), s.Perimetro())
}

circulo := Circulo{Raio: 5}
imprimirInfoForma(circulo)

12. Tratamento de Erros

Go usa tratamento de erros explícito em vez de exceções:

func lerArquivo(nomeArquivo string) (string, error) {
    dados, err := os.ReadFile(nomeArquivo)
    if err != nil {
        return "", fmt.Errorf("falha ao ler arquivo %s: %w", nomeArquivo, err)
    }
    return string(dados), nil
}

conteudo, err := lerArquivo("exemplo.txt")
if err != nil {
    fmt.Println("Erro:", err)
    return
}
fmt.Println("Conteúdo:", conteudo)

13. Concorrência com Goroutines

Goroutines são threads leves gerenciadas pelo runtime do Go:

func trabalhador(id int) {
    for i := 0; i < 3; i++ {
        fmt.Printf("Trabalhador %d: %d\n", id, i)
        time.Sleep(time.Millisecond * 100)
    }
}

func main() {
    // Inicia múltiplas goroutines
    for i := 1; i <= 3; i++ {
        go trabalhador(i)
    }

    // Aguarda as goroutines completarem
    time.Sleep(time.Second)
    fmt.Println("Todos os trabalhadores completaram")
}

14. Canais

Canais são usados para comunicação entre goroutines:

func produtor(ch chan<- int) {
    for i := 0; i < 5; i++ {
        ch <- i // Envia valor para o canal
        time.Sleep(time.Millisecond * 100)
    }
    close(ch) // Fecha o canal quando terminar
}

func consumidor(ch <-chan int) {
    for valor := range ch {
        fmt.Println("Recebido:", valor)
    }
}

func main() {
    ch := make(chan int, 3) // Canal com buffer

    go produtor(ch)
    consumidor(ch)

    fmt.Println("Comunicação por canal concluída")
}

15. Operações com Arquivos

Go fornece métodos simples para ler e escrever arquivos:

// Lendo arquivos
dados, err := os.ReadFile("exemplo.txt")
if err != nil {
    fmt.Println("Erro lendo arquivo:", err)
    return
}
fmt.Println("Conteúdo do arquivo:", string(dados))

// Escrevendo arquivos
conteudo := "Olá, Go!\n"
err = os.WriteFile("saida.txt", []byte(conteudo), 0644)
if err != nil {
    fmt.Println("Erro escrevendo arquivo:", err)
    return
}
fmt.Println("Arquivo escrito com sucesso")

16. Pacotes e Módulos

Módulos Go gerenciam dependências e versões de pacotes:

// Importando pacotes da biblioteca padrão
import (
    "fmt"
    "math"
    "strings"
)

func main() {
    fmt.Println(math.Sqrt(16))        // 4
    fmt.Println(strings.ToUpper("go")) // GO
}

Para criar seu próprio pacote, crie um diretório com o nome do seu pacote e exporte funções capitalizando seus nomes.

17. Testes

Go tem suporte integrado para testes:

// No arquivo math_test.go
package main

import "testing"

func TestAdicionar(t *testing.T) {
    resultado := adicionar(2, 3)
    esperado := 5
    if resultado != esperado {
        t.Errorf("adicionar(2, 3) = %d; esperado %d", resultado, esperado)
    }
}

func adicionar(a, b int) int {
    return a + b
}

Execute os testes com: go test

18. Melhores Práticas

  • Use gofmt para formatar seu código
  • Siga as convenções de nomenclatura do Go (camelCase para variáveis, PascalCase para exports)
  • Trate erros explicitamente
  • Use interfaces para abstração
  • Prefira composição sobre herança
  • Escreva testes abrangentes
  • Use a biblioteca padrão sempre que possível

Este tutorial cobre os recursos essenciais da programação em Go. Com prática, você será capaz de construir aplicações eficientes e concorrentes usando os recursos poderosos do Go.